# vi: tabstop=4 : expandtab : shiftwidth=4
from __future__ import division
import random
import color


def person_stat_updater(player, initial=False):
    """Gives the person their initial HP and MP upon character creation completion
    Once creation is complete, it is called in Person.tick() to keep stats updated in realtime."""
    if initial:
        player.XPToLevel = ((.5+player.level/2)*50*(.5+player.level/2))
        player.XPPrevious = ((.5+player.level/2)*50*(.5+player.level/2))
        player.old_XP = ((.5+player.level/2)*50*(.5+player.level/2))
        con = player.stats['con']
        intell = player.stats['int']
        player.maxHP = random.randint(con+3, int(con*1.4)+3)+\
                       random.randint(con+3, int(con*1.4)+3)
        player.maxMP = random.randint(intell+3, int(intell*1.4)+3)+\
                       random.randint(intell+3, int(intell*1.4)+3)
        player.HP = player.maxHP
        player.MP = player.maxMP
        player.baseHP = player.maxHP
        player.baseMP = player.maxMP
        player.stats['dodge'] = player.stats['dex']/3
        player.stats['accuracy'] = ((player.stats['str']+player.stats['dex'])/2)/3
        if 'mob' in player.attrs:
            player.deathexp = int((player.stats['str'] + player.stats['con'] + \
            player.stats['int'] + player.stats['dex'])/5)
    else:
        # This keeps dodge, acc and encumbrance alligned with stats without erasing bonuses gained from items.
        player.stats['encumbrance'] = (player.stats['str']+player.stats['con'])*5.2
        player.stats['dodge'] = player.stats['dex']/3 
        player.stats['accuracy'] = ((player.stats['str']+player.stats['dex'])/2)/3
        # To add something, simply add a reset statement like the 2 above this line, then add whatever is needed (below) to reapply additional stats
        from thing import fetch
        for uid in player.eq.values():
            if uid != None:
                item = fetch(uid)
                if item == None: continue
                for bonus in item.bonus.keys():
                    if bonus == 'dodge':
                        player.stats[bonus] += item.bonus[bonus]
                    if bonus == 'accuracy':
                        player.stats[bonus] += item.bonus[bonus]
                    if bonus == 'encumbrance':
                        player.stats[bonus] += item.bonus[bonus]
        for bonus in player.spellBonus.keys():
            if bonus == 'dodge':
                player.stats['dodge'] += player.spellBonus[bonus]
            if bonus == 'accuracy':
                player.stats['accuracy'] += player.spellBonus[bonus]
            if bonus == 'encumbrance':
                player.stats['encumbrance'] += player.spellBonus[bonus]

def levelup(player, con, intell, initial=False):
    """This part sets it so each 10 levels the curve will get steeper
     The formulas in their current state may need to be adjusted, I haven't charted
     it all out too much, but this makes for a solid starting point. the idea is to have it scale like a
     function, but still be pretty easy but then once you hit lvl 80, it slows way down. then those
     who are hardcore can keep going and those that aren't can be content with lvl 80. This also sets the level cap at 101
    """
    level = player.level
    if level < 17: lcalc = .5+level/2
    elif level > 79: lcalc = level*level/5
    else: lcalc = level/10*level/3
    if level < 100:
        # Loop leveling in case player receives enough xp to level more than once
        while player.XP > player.XPToLevel:
            player.level = level+1
            level = level+1
            player.hear("You begin to feel more powerful as you are hardened by your experiences!")
            player.hear("(You have attained level %s)" % level)
            # Get base stats, and calculate health & mana
            true_con = con
            true_intell = intell
            for uid in player.eq.values():
                if uid != None: 
                    from thing import fetch
                    item = fetch(uid)
                    if item.bonus['con']: true_con -= item.bonus['con']
                    if item.bonus['int']: true_intell -= item.bonus['con']
            for bonus in player.spellBonus.keys():
                if bonus == 'con': true_con -= bonus
                if bonus == 'int': true_intell -= bonus
            player.baseHP += random.randint(true_con-3, int(true_con*1.3)-3)
            player.baseMP += random.randint(true_intell-3, int(true_intell*1.3)-3)
            player.maxHP = player.baseHP
            player.maxMP = player.baseMP
            player.HP = player.maxHP
            player.MP = player.maxMP
            player.stats['statpoints'] += 2
            if level < 17: lcalc = .5+level/2
            elif level > 79: lcalc = level*level/5
            else: lcalc = level/10*level/3
            player.old_XP = player.XPToLevel
            player.XPToLevel = (lcalc*50*lcalc)
            player.XPPrevious = player.XPToLevel - player.old_XP

    if level == 100 and player.MaxLevelQuest == True and player.MaxLevel == False:
        if player.XP > (int(lcalc)*50*int(lcalc)):
            player.level = level+1
            level = level+1
            player.MaxLevel == True
            player.hear("Congratulations!!! You have won at leveling up! Now, go find something else to do!!")
            player.hear("(You are now the maximum level, %s)" % level)
            player.maxHP += random.randint(con, int(con*1.5))
            player.maxMP += random.randint(intell, int(intell*1.5))
            player.HP = player.maxHP
            player.MP = player.maxMP
            player.baseHP = player.maxHP
            player.baseMP = player.maxMP
            player.stats['statpoints'] += 5
            
    if 'mob' in player.attrs:
        from thing import fetch
        room = fetch(player.location)
        if player.oldlevel < level:
            while 1:
                player.maxHP += random.randint(con, int(con*1.3))
                player.maxMP += random.randint(intell, int(intell*1.3))
                player.stats['int'] += 1
                player.stats['con'] += 1
                player.stats['str'] += 1
                player.stats['dex'] += 1
                player.oldlevel += 1
                player.deathexp += ((player.stats['str'] + player.stats['con'] + \
                player.stats['int'] + player.stats['dex'])/5)
                if not initial: room.broadcast(player.name+" gains a level!")
                if player.oldlevel >= level: break
            if initial:
                player.HP = player.maxHP
                player.MP = player.maxMP
                if level < 17: lcalc = .5+(level-1)/2
                elif level > 79: lcalc = (level-1)*(level-1)/5
                else:lcalc = (level-1)/10*(level-1)/3
                player.XP = lcalc*lcalc*50

def expGain(player, mob):
    from thing import fetch
    partylist = []
    room = fetch(player.location)
    for partymember in room.contents:
        partymember = fetch(partymember)
        if partymember == None:return # In case a mob dies in combat and a different mob kills its target
        if "person" in partymember.attrs:
            if partymember.combatTarget == player.combatTarget:
                partylist.append(partymember)
    exp = int(mob.deathexp/len(partylist))
    for partymember in partylist:
        partymember.XP += exp
        partymember.hear("You gain "+str(exp)+" experience points!!")
        levelup(partymember, partymember.stats['con'], partymember.stats['int'])
        partymember.combatTarget = None


def attackDamage(attacker, defender):
    # Calculate damage if attacker is not hiding
    bonusDmg = 0
    DR = 0
    from thing import fetch
    for item in attacker.eq.keys():
        Object = fetch(attacker.eq[item])
        if Object == None: continue
        bonusDmg += Object.bonus['damage']
    for item in defender.eq.keys():
        Object = fetch(defender.eq[item])
        if Object == None: continue
        DR += Object.bonus['DR']
    DR += defender.spellBonus['DR']
    bonusDmg += attacker.spellBonus['damage']
    dexInt = (attacker.stats['dex']+attacker.stats['int'])
    if attacker.miscAttrs['hiding'] == False:
        # Check if player crits, then calc damage and set message
        if random.random() < ((dexInt/(dexInt+40)*9.5)*(dexInt/(dexInt+40)*7.0))*.01:
            critMsg = {1:'skillfully ', 2:'tactfully lunge forward and ', 3:'radically leap through the air and  ',
                       4:'critically ', 5:'let off an impressive battle cry and critically ', 6:'exploit a vulnerability and critically ',
                       7:'effortlessly, yet powerfully ', 8:'execute a powerful attack and '}
            critMsg2 = {1:'skillfully ', 2:'tactfully lunges forward and ', 3:'radically leaps through the air and ',
                        4:'critically ', 5:'lets of an impressive battle cry and critically ', 6:'exploits a vulnerability and critically ',
                        7:'effortlessly, yet powerfully ', 8:'executes a powerful attack and '}
            number = random.randint(1,7)
            attacker.miscAttrs['critMsg'] = critMsg[number]
            attacker.miscAttrs['critMsg2'] = critMsg2[number]
            dmgRange = random.randint(int(((attacker.stats["str"]*.6)*2)+ bonusDmg) , int((attacker.stats["str"]*1.4)+ bonusDmg)*2)-DR
            if dmgRange > 0: return dmgRange
            else: return 0
        # Calc combat damage, and set crit messages to 'blank'
        else:
            attacker.miscAttrs['critMsg'] = ''
            attacker.miscAttrs['critMsg2'] = ''
            dmgRange = random.randint(int((attacker.stats["str"]*.6) + bonusDmg) , int((attacker.stats["str"]*1.4)) + bonusDmg)-DR
            if dmgRange > 0: return dmgRange
            else: return 0
    # Calculate the epic damage this sneakin dude is about to haz done
    else:
        attacker.miscAttrs['critMsg'] = 'surprise back'
        attacker.miscAttrs['critMsg2'] = 'surprise back'
        dmgRange = random.randint(int((attacker.stats["str"]*.6*3.5)+ bonusDmg) , int(((attacker.stats["str"]*1.4)+ bonusDmg)*3.5))-DR
        if dmgRange > 0: return dmgRange
        else: return 0

def attackSpeed(attacker):
    speed = (attacker.stats['dex']*-1+55)+int((attacker.stats['weight']/attacker.stats['encumbrance'])*100)/4
    if speed <= 10:
        return 11
    else:
        return speed

def spelldamage(attacker):
    return random.randint(int(attacker.stats["int"]*.6), int(attacker.stats["int"]*1.4))
    
def getAttackType(player, person):
    # A dictionary of lists of verbs associated with weapon architectures
    if person == '1st':
        archVerb = {
        'edged':['slice', 'cut', 'slash', 'stab', 'hack'],
        'piercing':['stab', 'pierce', 'skewer', 'cut'],
        'blunt':['smack', 'hit', 'pound', 'bludgeon', 'thump'],
        'axe':['chop', 'hack', 'rend'],
        'ranged':['shoot', 'pierce'],
        'throwing':['hurl your weapon at','hurl your weapon at','hurl your weapon at', 'lob your weapon at','lob your weapon at'],
        'unarmed':['punch', 'punch', 'punch', 'strike', 'kick', 'kick', 'jab']
        }
        # Prevent circular import
        from thing import fetch
        # get weapon player is wielding
        weapon = fetch(player.eq['mainhand'])
        if weapon == None:
            weapon = fetch(player.eq['offhand'])
            if weapon == None:
                return random.choice(archVerb['unarmed'])
        return random.choice(archVerb[weapon.arch])
    elif person == '3rd':
        archVerb = {
        'edged':['slices', 'cuts', 'slashes', 'stabs', 'hacks'],
        'piercing':['stabs', 'pierces', 'skewers', 'cuts'],
        'blunt':['smacks', 'hits', 'pounds', 'bludgeons', 'thumps'],
        'axe':['chops', 'hacks', 'rends'],
        'ranged':['shoots', 'pierces'],
        'throwing':['hurls their weapon at','hurls their weapon at','hurls their weapon at', 'lobs their weapon at','lobs their weapon at'],
        'unarmed':['punches', 'punches', 'punches', 'strikes', 'kicks', 'kicks', 'jabs', 'jumpkicks']
        }
        # Prevent circular import
        from thing import fetch
        # get weapon player is wielding
        weapon = fetch(player.eq['mainhand'])
        if weapon == None:
            weapon = fetch(player.eq['offhand'])
            if weapon == None:
                return random.choice(archVerb['unarmed'])
        return random.choice(archVerb[weapon.arch])

def targetPrompt(target):
    if target == None:
        return ""
    else:
        target_hp_bar = "#"*int((int((round(float(target.HP)/float(target.maxHP), 2))*100)/10))
        target_hp_space = " "*(10 - int((int((round(float(target.HP)/float(target.maxHP), 2))*100)/10)))
        return target.name+"["+color.red+target_hp_bar+target_hp_space+color.reset+"] "

def prompt(self, target=None):
    """Returns health and mana information to the player
    as well as target health if inCombat is True"""
    chp = self.HP
    thp = self.maxHP
    cmana = self.MP
    tmana = self.maxMP
    hpcolor = color.green
    mpcolor = color.green
    x = color.reset
    if float(chp)/float(thp) < 0.30:
        hpcolor = color.red
    if float(cmana)/float(tmana) < 0.30:
        mpcolor = color.red
    if (float(chp)/float(thp))*100 in xrange(31,51):
        hpcolor = color.yellow
    if (float(cmana)/float(tmana))*100 in xrange(31,50):
        mpcolor = color.yellow
    if self.settings['promptBar'] == False:
        if self.stats['statpoints'] > 0:
            self.hear(" [HP:"+hpcolor+str(chp)+"/"+str(thp)+x+" - MP:"+mpcolor+str(cmana)+"/"+str(tmana)+x+"] LEVEL (type 'gain')")
        else:
            self.hear(" [HP:"+hpcolor+str(chp)+"/"+str(thp)+x+" - MP:"+mpcolor+str(cmana)+"/"+str(tmana)+x+"]")
    elif self.settings['promptBar']:
        #hpPercent = int(chp/thp)*100
        #mpPercent = int(tmana/cmana)*100
        hpBar = "#"*int((int((round(float(chp)/float(thp), 2))*100)/5))
        hpSpace = " "*(20 - int((int((round(float(chp)/float(thp), 2))*100)/5)))
        mpBar = "#"*int((int((round(float(cmana)/float(tmana), 2))*100)/5))
        mpSpace = " "*(20 - int((int((round(float(cmana)/float(tmana), 2))*100)/5)))
        if self.stats['statpoints'] >0:
            self.hear(" [HP:"+hpcolor+str(chp)+x+"["+hpcolor+hpBar+x+hpSpace+"]\
- MP:"+mpcolor+str(cmana)+x+"["+mpcolor+mpBar+x+mpSpace+"] "+targetPrompt(target)+"] LEVEL (type 'gain')")
        else:
            self.hear(" [HP:"+hpcolor+str(chp)+x+"["+hpcolor+hpBar+x+hpSpace+"]\
- MP:"+mpcolor+str(cmana)+x+"["+mpcolor+mpBar+x+mpSpace+"] "+targetPrompt(target))
